#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：back 
@File    ：member_dao.py
@IDE     ：PyCharm 
@Author  ：七分是你
@Date    ：2024/6/28 下午8:23 
@explain : 
"""

import time
from typing import Tuple, Optional

from sqlalchemy import desc, or_, and_, select
from sqlalchemy.orm import joinedload

from app.dao.models import XlxMember, XlxMemberPoints, XlxMemberPointsLog, XlxMemberActionLog, XlxCompany, XlxResume, \
    XlxMemberBind
from . import tools
from .base_dao import getDatabaseSession


class MemberQueryDao(object):
    """会员查询类"""

    @classmethod
    def member_list(cls, list_type: str = 'personal', where_clause: list = None, company_where_clause: list = None,
                    personal_where_clause: list = None, member_bind_where_clause: list = None, sort_by: str = 'uid',
                    page: int = 1,
                    page_size: int = 10) -> Tuple[int, list]:
        with getDatabaseSession() as session:
            total_query = session.query(XlxMember)

            # 根据 list_type 构建查询
            if list_type == 'company':
                total_query = total_query.outerjoin(XlxCompany, XlxMember.uid == XlxCompany.uid).filter(
                    XlxMember.utype == 1).filter(XlxCompany.companyname != '')
            elif list_type == 'personal':
                total_query = total_query.outerjoin(XlxResume, XlxMember.uid == XlxResume.uid).filter(
                    XlxMember.utype == 2).filter(
                    XlxResume.fullname != None)
            else:
                # 使用 or_ 构建复杂的 WHERE 条件
                total_query = total_query.outerjoin(XlxCompany, XlxMember.uid == XlxCompany.uid).outerjoin(XlxResume,
                                                                                                           XlxMember.uid == XlxResume.uid)
                total_query = total_query.filter(
                    or_(
                        and_(XlxCompany.companyname == None, XlxMember.utype == 1),
                        and_(XlxResume.fullname == None, XlxMember.utype == 2)
                    )
                )
            # 子查询，获取绑定了微信的用户的 uid
            subquery = select([XlxMemberBind.uid]).where(XlxMemberBind.type == 'weixin').group_by(
                XlxMemberBind.uid).alias('d')
            total_query = total_query.outerjoin(subquery, XlxMember.uid == subquery.c.uid)
            total_count = total_query.count()
            if where_clause:
                total_query = total_query.filter(*where_clause)
            if company_where_clause:
                total_query = total_query.filter(*company_where_clause)
            if personal_where_clause:
                total_query = total_query.filter(*personal_where_clause)
            if member_bind_where_clause:
                total_query = total_query.filter(*member_bind_where_clause)
                # 排序分页
            offset = (page - 1) * page_size
            if sort_by is None or sort_by == '':
                # 默认按照 uid 降序排序
                total_query = total_query.order_by(desc(XlxMember.uid))
            elif sort_by == 'last_login_time':
                # 按照 last_login_time 和 uid 降序排序
                total_query = total_query.order_by(desc(XlxMember.last_login_time), desc(XlxMember.uid))

            # 查询记录
            result = total_query.all()
        return total_count, result

    @classmethod
    def find_member_actionlog_list(cls, utype: int, where_clause: list, fulltext_clause, page: int = 1,
                                   page_size: int = 10) -> Tuple[int, list]:
        with getDatabaseSession() as session:
            # 计算总数（可选，因为通常分页查询不需要先计算总数）
            total_query = session.query(XlxMemberActionLog).filter(*where_clause).filter(
                fulltext_clause).count() if fulltext_clause else session.query(XlxMemberActionLog).filter(
                *where_clause).count()
            # 构建查询
            query = session.query(XlxMemberActionLog)
            if utype == 1:
                query = query.options(joinedload(XlxMemberActionLog.company)).join(XlxCompany,
                                                                                   XlxMemberActionLog.uid == XlxCompany.uid)
            elif utype == 2:
                query = query.options(joinedload(XlxMemberActionLog.resume)).join(XlxResume,
                                                                                  XlxMemberActionLog.uid == XlxResume.uid)
            query = query.filter(*where_clause)
            if fulltext_clause:
                query = query.filter(fulltext_clause)
            offset = (page - 1) * page_size
            query = query.order_by(XlxMemberActionLog.id.desc()).offset(offset).limit(page_size)
            result = query.all()
        return total_query, result

    @classmethod
    def find_member_action_log_list(cls, field_names: list = [], page: int = 1, page_size: int = 10, **kwargs) -> Tuple[
        int, list[XlxMemberActionLog]]:
        with getDatabaseSession() as session:
            valid_fields = [getattr(XlxMemberActionLog, field_name, None) for field_name in field_names if
                            hasattr(XlxMemberActionLog, field_name)]
            if not valid_fields:
                raise ValueError("No valid fields to select.")
            query = session.query(*valid_fields)
            query = tools.build_query(query, XlxMemberActionLog, **kwargs)
            total = query.count()
            # 排序分页
            offset = (page - 1) * page_size
            query = query.order_by(desc(XlxMemberActionLog.addtime)).offset(offset).limit(page_size)
            # 查询记录
            result = query.all()
        return total, result

    @classmethod
    def find_by_username(cls, username: str) -> XlxMember:
        with getDatabaseSession() as session:
            query = session.query(XlxMember)
            query = query.filter(XlxMember.username == username)
            result = query.first()
        return result

    @classmethod
    def find_member_list(cls, field_names: list = None, **kwargs) -> list[XlxMember]:
        with getDatabaseSession() as session:
            if field_names:
                valid_fields = [getattr(XlxMember, field_name, None) for field_name in field_names if
                                hasattr(XlxMember, field_name)]
                if not valid_fields:
                    raise ValueError("No valid fields to select.")
                query = session.query(*valid_fields)
            else:
                query = session.query(XlxMember)
            query = tools.build_query(query, XlxMember, **kwargs)
            result = query.all()
        return result

    @classmethod
    def find_member_info(cls, **kwargs) -> Tuple[Optional[XlxMember], Optional[int]]:
        with getDatabaseSession() as session:
            query = session.query(XlxMember, XlxMemberPoints.points).join(XlxMemberPoints)
            query = tools.build_query(query, XlxMember, **kwargs)
            result = query.first()
            if result is not None:
                member, points = result  # 注意这里可能会抛出异常，如果query没有正确设置
                # 如果points是None（即没有关联的记录），我们将其设置为一个默认值，比如0
                if points is None:
                    points = 0
                return member, points
            else:
                # 如果没有找到成员，返回None或者抛出异常，取决于您的业务需求
                return None, None  # 或者抛出异常

    @classmethod
    def find_member_points(cls, **kwargs) -> XlxMemberPoints:
        with getDatabaseSession() as session:
            query = session.query(XlxMemberPoints)
            query = tools.build_query(query, XlxMemberPoints, **kwargs)
            result = query.first()
        return result


class MemberOperateDao(object):
    """会员操作类DAO"""

    @classmethod
    def save_member(cls, data: dict) -> XlxMember:
        with getDatabaseSession() as session:
            new_user = XlxMember(**data)
            session.add(new_user)
            session.flush()
            session.commit()
        return new_user

    @classmethod
    def set_member_points(cls, data: dict, op: int = 1):
        param_points = data['points']
        check_points = MemberQueryDao.find_member_points(**{'uid': data['uid']})
        if not check_points:
            if op == 2:
                data['points'] = 0
            cls.save_member_points(data)
        else:
            if op == 1:
                data['points'] = check_points.points + data['points']
            elif op == 2:
                data['points'] = check_points.points - data['points']
            if data['points'] < 0:
                data['points'] = 0
            cls.save_member_points(data)
        if data['points'] > 0:
            log = {'uid': data['uid'], 'op': op, 'points': param_points, 'content': data['note'],
                   'addtime': int(time.time())}
            cls.save_member_points_log(log)

    @classmethod
    def save_member_points(cls, data: dict) -> XlxMemberPoints:
        with getDatabaseSession() as session:
            existing_points = session.query(XlxMemberPoints).filter_by(uid=data['uid']).first()
            if existing_points:
                existing_points.points = data['points']
            else:
                new_points = XlxMemberPoints(uid=data['uid'], points=data['points'])
                session.add(new_points)
            session.flush()
            session.commit()
        return existing_points or new_points

    @classmethod
    def save_member_points_log(cls, data: dict) -> XlxMemberPointsLog:
        with getDatabaseSession() as session:
            new_data = XlxMemberPointsLog(**data)
            session.add(new_data)
            session.flush()
            session.commit()
        return new_data
